home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 1.iso / toolbox / src / demos / OpenGL / walker / walker.c < prev    next >
C/C++ Source or Header  |  1996-11-11  |  28KB  |  1,106 lines

  1. #include <GL/gl.h>
  2. #include <GL/glu.h>
  3. #include <GL/glut.h>
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <math.h>
  7. #include <string.h>
  8. #include <dirent.h>
  9. #include <assert.h>
  10.  
  11. #include "walker.h"
  12.  
  13.  
  14.  
  15. #define MAX(x,y) ((x) > (y) ? (x) : (y))
  16. #define MIN(x,y) ((x) < (y) ? (x) : (y))
  17.  
  18. #define CYCLE_SIZE 100
  19. #define CYCLE_STEP 1.0/CYCLE_SIZE
  20. #define OVERSAMPLE 10
  21.  
  22. #define MAX_CPOINTS 34   /* 2 end point ones and 10 in the middle */
  23.  
  24. #define MAX_CSETNAMELEN 25
  25.  
  26. #define NUM_JOINTS 5
  27.  
  28. #define CSET_EXT ".cset"
  29. #define CSET_EXTLEN 5
  30.  
  31. #include "walkviewer.h"
  32.  
  33.  
  34. typedef enum { CMENU_QUIT, CMENU_CURVE, CMENU_HORIZ, CMENU_RESET,
  35.                CMENU_WALK, CMENU_DONEEDIT, CMENU_SAVE, CMENU_LOAD,
  36.            CMENU_MIRROR
  37.               } CurveMenuChoices;
  38.  
  39. typedef enum { WIRECUBE, SOLIDCUBE, CYLINDER1, CYLINDER2 } ModelTypes;
  40.  
  41. int GuyModel = SOLIDCUBE;
  42.  
  43. /***************************************************************/
  44. /*************************** GLOBALS ***************************/
  45. /***************************************************************/
  46.  
  47. GLuint HorizontalList, AxesList,     /* Display lists */
  48.        CurveLists, ControlPtsLists;  /* Firsts of groups of display lists */
  49.  
  50. int CurveAsPoints   =  0,    /* Display curve as points? */
  51.     DrawHorizontals =  0,    /* Draw horizontal lines?   */
  52.     EditingCurve    = -1;    /* Editing what curve, -1 means none */
  53.  
  54. int CurveWindow,   /* Glut window id's to two top level windows */
  55.     GuyWindow;
  56.  
  57. int MirrorLegs = 0;
  58.  
  59. int CurveMenu     = -1,
  60.     CurveEditMenu = -1,
  61.     StepSizeMenu  = -1,
  62.     LoadMenu      = -1,
  63.     SaveMenu      = -1;
  64.  
  65. char *CSetNames[MAX_CSETNAMELEN];
  66.  
  67. int CurrentCurve = -1;  /* Curve loaded, index to CSetNames */
  68.  
  69. GLfloat Walk_cycle[2][NUM_JOINTS][CYCLE_SIZE];  /* array of computed angles */
  70.  
  71. int Step = CYCLE_SIZE/2;  /* Position in cycle, start in middle */
  72.  
  73. float fStep = CYCLE_SIZE/2;   /* floating point for non-integer steping */
  74. float IncStep = 1.0;
  75.  
  76. typedef struct ControlPts {
  77.   int numpoints;
  78.   float xcoords[MAX_CPOINTS];
  79.   float angles[MAX_CPOINTS];
  80. } tControlPts;
  81.  
  82. tControlPts RotCurve[NUM_JOINTS];   /* series of cntrl points for ea joint */
  83.  
  84. int Walking         = 0,     /* Guy is walking? */
  85.     ViewPerspective = 1,     /* Perspective or orthographic views */
  86.     DrawAxes        = 0;     /* Draw axes for alignment */
  87.  
  88. int CurveWWidth,             /* Dimensions of curve window */
  89.     CurveWHeight;  
  90.  
  91. int CurveDownBtn = -1,               /* mouse stuff, for editing curves */
  92.     WasWalking,
  93.     CurvePickedPoint = -1,
  94.     CurveLastX,
  95.     CurveLastY;
  96.  
  97. int CurveWindowVisible = 1;
  98.  
  99.  
  100.   /* prototypes */
  101. void RedisplayBoth(void);
  102. void IncrementStep(void);
  103. void CurveCPointDrag(void);
  104. void CurveHandleMenu(int value);
  105. void StopWalking(void);
  106. void CurveHandleEditMenu(int curve);
  107. void ComputeCSetAndMakeLists(void);
  108. int MakeLoadAndSaveMenus(void);
  109. void CurveMenuInit(void);
  110. void SetWindowTitles(char *csetname);
  111.  
  112. /***************************************************************/
  113. /**************************** BEZIER ***************************/
  114. /***************************************************************/
  115.  
  116.   /* Matrix times a vector  dest = m*v */
  117. void MultMV(float m[3][4], float v[4], float dest[3])
  118. {
  119.   int i, j;
  120.  
  121.   for (i = 0; i < 3; i++) {
  122.     dest[i] = 0;
  123.     for (j = 0; j < 4; j++)
  124.       dest[i] += m[i][j] * v[j];
  125.   }
  126. }
  127.  
  128.   /* Matrix multiplication, dest = m1*m2 */
  129. void MultM(float m1[3][4], float m2[4][4], float dest[3][4])
  130. {
  131.   int i, j, k;
  132.  
  133.   for (i = 0; i < 3; i++)
  134.     for (j = 0; j < 4; j++) {
  135.       dest[i][j] = 0;
  136.       for (k = 0; k < 4; k++)
  137.       dest[i][j] += (m1[i][k] * m2[k][j]);
  138.     }
  139. }
  140.  
  141. void ComputeCurve(int joint)
  142. {
  143.   float prod[3][4], tm[4], pos[3];
  144.   float t = 0, tinc = (float)CYCLE_STEP/OVERSAMPLE;
  145.   int ctlpoint, i;
  146.   float BBasis[4][4] = {{-1, 3, -3, 1}, {3, -6, 3, 0},
  147.                         {-3, 3,  0, 0}, {1,  0, 0, 0}};
  148.   int lastindex, newindex;
  149.  
  150.   float pointset[3][4];
  151.   for (i = 0; i < 4; i++)   /* z's are always zero, only 2-d */
  152.     pointset[2][i] = 0; 
  153.  
  154.   lastindex = -1;
  155.   for(ctlpoint = 0; ctlpoint < RotCurve[joint].numpoints; ctlpoint += 3) {
  156.     t = 0;
  157.     for (i = 0; i < 4; i++)
  158.       pointset[0][i] = RotCurve[joint].xcoords[ctlpoint + i];
  159.     for (i = 0; i < 4; i++)
  160.       pointset[1][i] = RotCurve[joint].angles[ctlpoint + i];
  161.  
  162.     MultM(pointset, BBasis, prod);
  163.  
  164.     while (t <= 1) {
  165.       tm[0] = t*t*t;
  166.       tm[1] = t*t;
  167.       tm[2] = t;
  168.       tm[3] = 1;
  169.       MultMV(prod, tm, pos);
  170.       newindex = (int)(pos[0]*(CYCLE_SIZE-1));
  171.       if ((int)(newindex > lastindex))  {  /* go at least one */
  172.     Walk_cycle[0][joint][newindex] = pos[1];
  173.     lastindex++;
  174.       } 
  175.       t += tinc;
  176.     }
  177.   }
  178.  
  179.   for (i = 0; i < CYCLE_SIZE; i++) {      /* copy to other leg, out-o-phase */
  180.     if (MirrorLegs)
  181.       Walk_cycle[1][joint][i] =
  182.         Walk_cycle[0][joint][i];
  183.     else
  184.       Walk_cycle[1][joint][i] =
  185.         Walk_cycle[0][joint][(i+(CYCLE_SIZE/2))%CYCLE_SIZE];
  186.   }
  187. }
  188.  
  189. /***************************************************************/
  190. /************************* CURVE I/O ***************************/
  191. /***************************************************************/
  192.  
  193. void FlatCSet(void)
  194. {
  195.   int joint;
  196.  
  197.   for (joint = 0; joint < NUM_JOINTS; joint++) {
  198.     RotCurve[joint].numpoints = 4;
  199.     RotCurve[joint].xcoords[0] = 0.0;
  200.     RotCurve[joint].angles[0]  = 0.0;
  201.     RotCurve[joint].xcoords[1] = 0.2;
  202.     RotCurve[joint].angles[1]  = 0.0;
  203.     RotCurve[joint].xcoords[2] = 0.8;
  204.     RotCurve[joint].angles[2]  = 0.0;
  205.     RotCurve[joint].xcoords[3] = 1.0;
  206.     RotCurve[joint].angles[3]  = 0.0;
  207.   }
  208. }
  209.  
  210. int ReadCSetFromFile(char *filename)
  211. {
  212.   FILE *infile = fopen(filename, "r");
  213.   int numjoints, numpoints, joint, point, mirrorlegs;
  214.   float value;
  215.  
  216.   if (infile == NULL)
  217.     goto abort;
  218.   
  219.   if (!fscanf(infile, " %d", &numjoints) || numjoints != NUM_JOINTS)
  220.     goto abort;
  221.  
  222.   if (!fscanf(infile, " %d", &mirrorlegs) || (mirrorlegs != 0 &&
  223.                                               mirrorlegs != 1))
  224.     goto abort;
  225.  
  226.   MirrorLegs = mirrorlegs;
  227.  
  228.   for (joint = 0; joint < NUM_JOINTS; joint++) {
  229.     if (!fscanf(infile, " %d", &numpoints) || numpoints < 4 || 
  230.                                               numpoints > MAX_CPOINTS)
  231.       goto abort;
  232.     RotCurve[joint].numpoints = numpoints;
  233.     for (point = 0; point < numpoints; point++) {
  234.       if (!fscanf(infile, " %f", &value))
  235.     goto abort;
  236.       RotCurve[joint].xcoords[point] = value;
  237.     }
  238.     for (point = 0; point < numpoints; point++) {
  239.       if (!fscanf(infile, " %f", &value))
  240.     goto abort;
  241.       RotCurve[joint].angles[point] = value;
  242.     }
  243.   }
  244.  
  245.   fclose(infile);
  246.   return 0;
  247.  
  248.   abort:
  249.     fclose(infile);
  250.     fprintf(stderr, "Something went wrong while reading file %s\n", filename);
  251.     FlatCSet();
  252.     return -1;
  253. }
  254.  
  255. void WriteCSetToFile(char *filename)
  256. {
  257.   FILE *outfile = fopen(filename, "w+");
  258.   int joint, point;
  259.  
  260.   if (outfile == NULL) {
  261.     fprintf(stderr, "Error: could not create file %s\n", filename);
  262.     return;
  263.   }
  264.  
  265.   fprintf(outfile, "%d\n", NUM_JOINTS);
  266.  
  267.   fprintf(outfile, "%d\n", MirrorLegs);
  268.  
  269.   for (joint = 0; joint < NUM_JOINTS; joint++) {
  270.  
  271.     fprintf(outfile, "%d\n", RotCurve[joint].numpoints);
  272.  
  273.     for (point = 0; point < RotCurve[joint].numpoints; point++) {
  274.       fprintf(outfile, "%f ", RotCurve[joint].xcoords[point]);
  275.     }
  276.     fprintf(outfile, "\n");
  277.  
  278.     for (point = 0; point < RotCurve[joint].numpoints; point++) {
  279.       fprintf(outfile, "%f ", RotCurve[joint].angles[point]);
  280.     }
  281.     fprintf(outfile, "\n");
  282.   }
  283.  
  284.   fclose(outfile);
  285. }
  286.  
  287. void HandleLoadMenu(int cset)
  288. {
  289.   char filename[MAX_CSETNAMELEN + CSET_EXTLEN + 1];
  290.  
  291.   if (cset == -1) {
  292.     MakeLoadAndSaveMenus();
  293.     CurveMenuInit();
  294.   } else {
  295.     (void)strcpy(filename, CSetNames[cset]);
  296.     (void)strcat(filename, CSET_EXT);
  297.     if (ReadCSetFromFile(filename) == 0) {
  298.       glutSetMenu(SaveMenu);
  299.       glutChangeToMenuEntry(1, CSetNames[cset], cset);
  300.       ComputeCSetAndMakeLists();
  301.       SetWindowTitles(CSetNames[cset]);
  302.       RedisplayBoth();
  303.     }
  304.   }
  305. }
  306.  
  307. void HandleSaveMenu(int cset)
  308. {
  309.   char filename[MAX_CSETNAMELEN + CSET_EXTLEN + 1];
  310.  
  311.   (void)strcpy(filename, CSetNames[cset]);
  312.   (void)strcat(filename, CSET_EXT);
  313.   WriteCSetToFile(filename);
  314.   ComputeCSetAndMakeLists();
  315.   RedisplayBoth();
  316. }
  317.  
  318. int MakeLoadAndSaveMenus(void)
  319. {
  320.   DIR *dirp = opendir(".");
  321.   struct dirent *direntp;
  322.   int csetnum = 0;
  323.   char *newcsetname;
  324.  
  325.   if (LoadMenu != -1)
  326.     glutDestroyMenu(LoadMenu);
  327.   if (SaveMenu != -1)
  328.     glutDestroyMenu(SaveMenu);
  329.  
  330.   SaveMenu = glutCreateMenu(HandleSaveMenu);
  331.   LoadMenu = glutCreateMenu(HandleLoadMenu);
  332.  
  333.   if (dirp == NULL) {
  334.     fprintf(stderr, "Error opening current dir in MakeLoadAndSaveMenus\n");
  335.     return(0);
  336.   }
  337.  
  338.   while ((direntp = readdir(dirp)) != NULL) {
  339.     char *ext = direntp->d_name + (strlen(direntp->d_name) - CSET_EXTLEN);
  340.     if (!strcmp(ext, CSET_EXT)) {
  341.       newcsetname = malloc(strlen(direntp->d_name) - CSET_EXTLEN + 1);
  342.       strncpy(newcsetname, direntp->d_name,
  343.           strlen(direntp->d_name) - CSET_EXTLEN);
  344.       newcsetname[strlen(direntp->d_name) - CSET_EXTLEN] = 0;
  345.       CSetNames[csetnum] = newcsetname;
  346.       glutAddMenuEntry(newcsetname, csetnum++);
  347.     }
  348.   }
  349.   closedir(dirp);
  350.   glutSetMenu(LoadMenu);
  351.   glutAddMenuEntry("-> Rescan Directory <-", -1);
  352.   glutSetMenu(SaveMenu);
  353.   CSetNames[csetnum] = "NewCurve0";
  354.   glutAddMenuEntry("NewCurve0", csetnum++);
  355.   CSetNames[csetnum] = "NewCurve1";
  356.   glutAddMenuEntry("NewCurve1", csetnum++);
  357.   CSetNames[csetnum] = "NewCurve2";
  358.   glutAddMenuEntry("NewCurve2", csetnum++);
  359.  
  360.   return (csetnum - 2);  /* just indicate curves in Load menu */
  361. }
  362.  
  363.  
  364. /***************************************************************/
  365. /********************* DISPLAY LISTS ***************************/
  366. /***************************************************************/
  367.  
  368.  
  369. void MakeCurveList(int joint)
  370. {
  371.   int i;
  372.  
  373.   glNewList(CurveLists+joint, GL_COMPILE);
  374.   glColor3f(1, 1, 1);
  375.   for (i = 0; i < CYCLE_SIZE; i++) {
  376.     glVertex3f((GLfloat)i/CYCLE_SIZE, Walk_cycle[0][joint][i]/180, 0);
  377.   }
  378.   glEndList();
  379. }
  380.  
  381. void MakeCPointList(int joint)
  382. {
  383.   int point;
  384.  
  385.   glNewList(ControlPtsLists+joint, GL_COMPILE);
  386.  
  387.     glColor3f(0, 0.4, 0);
  388.     glBegin(GL_LINE_STRIP);
  389.     for (point = 0; point < RotCurve[joint].numpoints; point++) {
  390.       if (!((point-2) % 3)) {
  391.         glEnd();
  392.         glBegin(GL_LINE_STRIP);
  393.       }
  394.       glVertex3f(RotCurve[joint].xcoords[point],
  395.              (RotCurve[joint].angles[point])/180.0, 0.0);
  396.     }
  397.     glEnd();
  398.  
  399.     glBegin(GL_POINTS);
  400.     for (point = 0; point < RotCurve[joint].numpoints; point++) {
  401.       if (point % 3)
  402.         glColor3f(0, 0.7, 0);
  403.       else
  404.         glColor3f(0.7, 0.0, 0);
  405.       glVertex3f(RotCurve[joint].xcoords[point],
  406.              (RotCurve[joint].angles[point])/180, 0);
  407.     }
  408.     glEnd();
  409.  
  410.   glEndList();
  411. }
  412.  
  413. void MakeJointLists(int joint)
  414. {
  415.   MakeCurveList(joint);
  416.   MakeCPointList(joint);
  417. }
  418.  
  419.  
  420. void ComputeCSetAndMakeLists(void)
  421. {
  422.   int joint;
  423.  
  424.   for(joint = 0; joint < NUM_JOINTS; joint++) {
  425.     ComputeCurve(joint);
  426.     MakeJointLists(joint);
  427.   }
  428. }
  429.  
  430. void MakeLists(void)
  431. {
  432.   HorizontalList = glGenLists(1);
  433.   glNewList(HorizontalList, GL_COMPILE);
  434.   {
  435.     float line1 = 25.0/180,
  436.           line2 = 35.0/180,
  437.           line3 = 45.0/180;
  438.     glColor3f(0, 0, 0.7);
  439.     glPushAttrib(GL_ENABLE_BIT);
  440.     glEnable(GL_LINE_STIPPLE);
  441.     glBegin(GL_LINES);
  442.       glVertex3f(0, 0, 0.5);
  443.       glVertex3f(1, 0, 0.5);
  444.       glVertex3f(0, line1, 0.5);  glVertex3f(1, line1, 0.5);
  445.       glVertex3f(0, -line1, 0.5); glVertex3f(1, -line1, 0.5);
  446.       glVertex3f(0, line2, 0.5);  glVertex3f(1, line2, 0.5);
  447.       glVertex3f(0, -line2, 0.5); glVertex3f(1, -line2, 0.5);
  448.       glVertex3f(0, line3, 0.5);  glVertex3f(1, line3, 0.5);
  449.       glVertex3f(0, -line3, 0.5); glVertex3f(1, -line3, 0.5);
  450.     glEnd();
  451.     glPopAttrib();
  452.   }
  453.   glEndList();
  454.  
  455.  
  456.   CurveLists = glGenLists(NUM_JOINTS);
  457.   assert(CurveLists != 0);
  458.  
  459.   ControlPtsLists = glGenLists(NUM_JOINTS);
  460.   assert(ControlPtsLists != 0);
  461.  
  462.   ComputeCSetAndMakeLists();
  463. }
  464.  
  465. /***************************************************************/
  466. /********************* curve WINDOW ****************************/
  467. /***************************************************************/
  468.  
  469. void CurveReshape(int w, int h)
  470. {
  471.   glViewport(0,0,w,h);
  472.   CurveWWidth = w; 
  473.   CurveWHeight = h;
  474.   glFlush();
  475. }
  476.  
  477. void CurveDisplay(void)
  478. {
  479.   int joint, otherlegstep;
  480.  
  481.   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  482.  
  483.   glPushMatrix();
  484.   glTranslatef(0, 0.5, 0);
  485.  
  486.   for (joint = NUM_JOINTS-1; joint >= 0; joint--) {
  487.  
  488.     if (DrawHorizontals) 
  489.       glCallList(HorizontalList);
  490.  
  491.     (CurveAsPoints) ?
  492.     glBegin(GL_POINTS) :
  493.     glBegin(GL_LINE_STRIP);
  494.       glCallList(CurveLists+joint);
  495.     glEnd();
  496.  
  497.     if (joint == EditingCurve) { 
  498.       glPointSize(5.0);
  499.       glCallList(ControlPtsLists+EditingCurve);
  500.       glPointSize(1.0);
  501.     }
  502.   glTranslatef(0, 1, 0);
  503.   }
  504.  
  505.   glPopMatrix();
  506.  
  507.   otherlegstep = (Step+50) % CYCLE_SIZE;
  508.     /* draw vertical line */
  509.   glColor3f(1, 1, 1);
  510.   glBegin(GL_LINES);
  511.     glVertex3f((GLfloat)Step/CYCLE_SIZE, 0, 0);
  512.     glVertex3f((GLfloat)Step/CYCLE_SIZE, NUM_JOINTS, 0);
  513.     if (!MirrorLegs) {
  514.       glVertex3f((GLfloat)otherlegstep/CYCLE_SIZE, 0, 0);
  515.       glVertex3f((GLfloat)otherlegstep/CYCLE_SIZE, NUM_JOINTS, 0);
  516.     }
  517.   glEnd();
  518.  
  519.   glFlush();
  520.   glutSwapBuffers();
  521. }
  522.  
  523.  
  524. void CurveGLInit(void)
  525. {
  526.   glMatrixMode(GL_PROJECTION);
  527.   glLoadIdentity();
  528.   glOrtho(0,1,0,NUM_JOINTS,1,-1);
  529.  
  530.   glMatrixMode(GL_MODELVIEW);
  531.   glLoadIdentity();
  532.  
  533.   glLineStipple(1, 0x00FF);
  534.  
  535.   glEnable(GL_DEPTH_TEST);
  536.   glDepthFunc(GL_LEQUAL);
  537.  
  538.  
  539.   glFlush();
  540.  
  541.  
  542.  
  543.  
  544. void CurveHandleButton(int button, int state, int x, int y)
  545. {
  546.   if (button == GLUT_RIGHT_BUTTON )
  547.     return;
  548.  
  549.   if (state == GLUT_DOWN && CurveDownBtn == -1) {
  550.     if (button == GLUT_MIDDLE_BUTTON)
  551.       CurveHandleMenu(CMENU_WALK);
  552.     else
  553.       fStep = Step = (int)((float)x/glutGet(GLUT_WINDOW_WIDTH) * CYCLE_SIZE);
  554.       
  555.     CurveDownBtn = button;
  556.  
  557.     WasWalking = Walking;
  558.     StopWalking();
  559.     RedisplayBoth();
  560.   } else if (button == CurveDownBtn) {
  561.     CurveDownBtn = -1;
  562.     if (WasWalking) {
  563.       Walking = 1;
  564.       agvSetAllowIdle(0);
  565.       glutIdleFunc(IncrementStep);    
  566.     }
  567.   }
  568. }
  569.  
  570. float CurveEditConstrain(float fx)
  571. {
  572.   if (CurvePickedPoint == 0)
  573.     fx = 0;
  574.   else if (CurvePickedPoint == RotCurve[EditingCurve].numpoints-1)
  575.     fx = 1;
  576.   else if (!(CurvePickedPoint % 3)) {  /* is a pivot */
  577.     fx = MAX(fx, RotCurve[EditingCurve].xcoords[CurvePickedPoint-1]);
  578.     fx = MIN(fx, RotCurve[EditingCurve].xcoords[CurvePickedPoint+1]);   
  579.     fx = MAX(fx, RotCurve[EditingCurve].xcoords[CurvePickedPoint-3]);
  580.     fx = MIN(fx, RotCurve[EditingCurve].xcoords[CurvePickedPoint+3]);       
  581.   } else if (!((CurvePickedPoint - 1) % 3)) {   /* is right slope */
  582.     fx = MAX(fx, RotCurve[EditingCurve].xcoords[CurvePickedPoint-1]);
  583.   } else {
  584.     fx = MIN(fx, RotCurve[EditingCurve].xcoords[CurvePickedPoint+1]);
  585.   } 
  586.   return fx;
  587. }
  588.  
  589. void RemovePoint(int pt)
  590. {
  591.   int i;
  592.  
  593.   for (i = pt - 1; i < RotCurve[EditingCurve].numpoints; i++) {
  594.     RotCurve[EditingCurve].xcoords[i] = RotCurve[EditingCurve].xcoords[i+3];
  595.     RotCurve[EditingCurve].angles[i]  = RotCurve[EditingCurve].angles[i+3];
  596.   }
  597.   RotCurve[EditingCurve].numpoints -= 3;
  598. }
  599.  
  600. void AddPoint(float fx)
  601. {
  602.   int i, j;
  603.  
  604.   if (fx < 0.05 || fx > 0.95 || RotCurve[EditingCurve].numpoints + 3 >=
  605.                                 MAX_CPOINTS)
  606.     return;
  607.  
  608.   for (i = 3; i < RotCurve[EditingCurve].numpoints; i += 3) {
  609.     if (fx < RotCurve[EditingCurve].xcoords[i]) {
  610.       for (j = RotCurve[EditingCurve].numpoints + 2; j > i + 1; j--) { 
  611.         RotCurve[EditingCurve].xcoords[j] =
  612.                 RotCurve[EditingCurve].xcoords[j-3];
  613.         RotCurve[EditingCurve].angles[j] =
  614.                 RotCurve[EditingCurve].angles[j-3];
  615.       }
  616.     RotCurve[EditingCurve].xcoords[i]   = fx;
  617.     RotCurve[EditingCurve].angles[i]    =
  618.       Walk_cycle[0][EditingCurve][(int)(fx*CYCLE_SIZE)];
  619.     RotCurve[EditingCurve].xcoords[i-1] = fx - 0.05;
  620.     RotCurve[EditingCurve].angles[i-1]  =
  621.       Walk_cycle[0][EditingCurve][(int)((fx-0.05)*CYCLE_SIZE)];
  622.     RotCurve[EditingCurve].xcoords[i+1] = fx + 0.05;
  623.     RotCurve[EditingCurve].angles[i+1]  = 
  624.       Walk_cycle[0][EditingCurve][(int)((fx+0.05)*CYCLE_SIZE)];
  625.     RotCurve[EditingCurve].numpoints += 3;
  626.     break;
  627.     }
  628.   }  
  629. }
  630.  
  631.  
  632. void CurveEditHandleButton(int button, int state, int x, int y)
  633. {
  634.   float fx, fy;
  635.   int point;
  636.  
  637.   fy = -(((float)y - ((float)CurveWHeight/NUM_JOINTS * EditingCurve)) /
  638.        ((float)CurveWHeight/NUM_JOINTS) - 0.5) * 180.0,
  639.   fx = (float)x/CurveWWidth;
  640.   
  641.   if (state == GLUT_DOWN && button == GLUT_LEFT_BUTTON &&
  642.                             CurveDownBtn == -1) {
  643.     CurvePickedPoint = -1;
  644.     
  645.     for (point = 0; point < RotCurve[EditingCurve].numpoints; point++) {
  646.       if (fabs(RotCurve[EditingCurve].xcoords[point] - fx) < 0.01 &&
  647.       fabs(RotCurve[EditingCurve].angles[point] - fy) < 4) {
  648.     CurvePickedPoint = point;
  649.     CurveLastX = x;
  650.     CurveLastY = y;
  651.     glutIdleFunc(CurveCPointDrag);
  652.     break;
  653.       }
  654.     }
  655.    if (CurvePickedPoint == -1)
  656.      CurveHandleButton(button, state, x, y);
  657.     CurveDownBtn = button;
  658.  
  659.  
  660.   } else if (state == GLUT_DOWN && button == GLUT_MIDDLE_BUTTON &&
  661.                                    CurveDownBtn == -1) {
  662.  
  663.     for (point = 3; point < RotCurve[EditingCurve].numpoints - 1; point += 3) {
  664.       if (fabs(RotCurve[EditingCurve].xcoords[point] - fx) < 0.01 &&
  665.       fabs(RotCurve[EditingCurve].angles[point] - fy) < 4) {
  666.     break;
  667.       }
  668.     }
  669.     if (point >= 3 && point < RotCurve[EditingCurve].numpoints - 1)
  670.       RemovePoint(point);
  671.     else if (fabs(Walk_cycle[0][EditingCurve][(int)(fx*CYCLE_SIZE)] - fy) < 4)
  672.       AddPoint(fx);
  673.     ComputeCurve(EditingCurve);
  674.     MakeJointLists(EditingCurve);    
  675.     RedisplayBoth();
  676.  
  677.   } else if (button == GLUT_LEFT_BUTTON && button == CurveDownBtn) {
  678.  
  679.     y = MAX(y, 0); y = MIN(y, CurveWHeight);
  680.     x = MAX(x, 0); x = MIN(x, CurveWWidth);
  681.     fy = -(((float)y - ((float)CurveWHeight/NUM_JOINTS * EditingCurve)) /
  682.          ((float)CurveWHeight/NUM_JOINTS) - 0.5) * 180.0,
  683.     fx = (float)x/CurveWWidth;
  684.     CurveDownBtn = -1;
  685.     if (CurvePickedPoint != -1) {
  686.       fx = CurveEditConstrain(fx);
  687.       RotCurve[EditingCurve].xcoords[CurvePickedPoint] = fx;
  688.       RotCurve[EditingCurve].angles[CurvePickedPoint] = fy;        
  689.       ComputeCurve(EditingCurve);
  690.       MakeJointLists(EditingCurve);
  691.       glutIdleFunc(NULL);
  692.       RedisplayBoth();
  693.     }
  694.   }
  695. }  
  696.  
  697.  
  698. void CurveHandleMotion(int x, int y)
  699. {
  700.   if (CurvePickedPoint == -1) { 
  701.     
  702.     if (CurveDownBtn == GLUT_LEFT_BUTTON || CurveDownBtn ==
  703.                                             GLUT_MIDDLE_BUTTON) {
  704.       Step = (int)((float)x/glutGet(GLUT_WINDOW_WIDTH) * CYCLE_SIZE)
  705.     % CYCLE_SIZE;
  706.       if (Step < 0)
  707.     Step = CYCLE_SIZE + Step;
  708.       fStep = Step;
  709.  
  710.     RedisplayBoth();
  711.     }
  712.   } else {
  713.     y = MAX(y, 0); y = MIN(y, CurveWHeight);
  714.     x = MAX(x, 0); x = MIN(x, CurveWWidth);
  715.     CurveLastX = x;
  716.     CurveLastY = y;
  717.   }
  718. }
  719.  
  720. void CurveCPointDrag(void)
  721. {
  722.   float fx, fy;
  723.  
  724.   if (CurveDownBtn == GLUT_LEFT_BUTTON && CurvePickedPoint != -1) {
  725.     fy = -(((float)CurveLastY -
  726.            ((float)CurveWHeight/NUM_JOINTS * EditingCurve)) /
  727.           ((float)CurveWHeight/NUM_JOINTS) - 0.5) * 180.0,
  728.     fx = (float)CurveLastX/CurveWWidth;
  729.  
  730.     fx = CurveEditConstrain(fx);
  731.     RotCurve[EditingCurve].xcoords[CurvePickedPoint] = fx;
  732.     RotCurve[EditingCurve].angles[CurvePickedPoint] = fy;        
  733.     ComputeCurve(EditingCurve);
  734.     MakeJointLists(EditingCurve);
  735.     RedisplayBoth();
  736.   }
  737. }
  738.  
  739. void CurveHandleKeys(unsigned char key, int x, int y)
  740. {
  741.   if (key > '0' && key < '9')
  742.     CurveHandleEditMenu((key-'0')-1);
  743.   else if (key == 'd')
  744.     CurveHandleMenu(CMENU_DONEEDIT);
  745.   else {
  746.     switch(key) {
  747.       case 'f':
  748.       case ' ': Step++;
  749.                 StopWalking(); break;
  750.       case 'F': Step += 5;
  751.                 StopWalking(); break;
  752.       case 'b': Step--;
  753.                 StopWalking(); break;
  754.       case 'B': Step -= 5; 
  755.                 StopWalking(); break;
  756.     }
  757.     Step %= CYCLE_SIZE;
  758.     if (Step < 0)
  759.       Step = CYCLE_SIZE + Step;
  760.     fStep = Step;
  761.     RedisplayBoth();
  762.   }
  763. }
  764.  
  765. void CurveHandleEditMenu(int curve)
  766. {
  767.   if (curve >= NUM_JOINTS)
  768.     return;
  769.   if (EditingCurve == -1) {
  770.     WasWalking = Walking;
  771.     Walking = 0;
  772.     agvSetAllowIdle(0);   /* don't allow spinning, just slows us down */
  773.     glutIdleFunc(NULL);
  774.     glutMouseFunc(CurveEditHandleButton);
  775.   }
  776.   EditingCurve = curve;
  777.   glutPostRedisplay();
  778. }
  779.  
  780. void CurveHandleSZMenu(int size)
  781. {
  782.   IncStep = (float)size/100;
  783. }
  784.  
  785. void CurveHandleMenu(int value)
  786. {
  787.   switch (value) {
  788.     case CMENU_QUIT:
  789.       exit(0);
  790.       break;
  791.     case CMENU_CURVE:
  792.       CurveAsPoints = !CurveAsPoints;
  793.       glutPostRedisplay();
  794.       break;
  795.     case CMENU_HORIZ:
  796.       DrawHorizontals = !DrawHorizontals;
  797.       glutPostRedisplay();
  798.       break;
  799.     case CMENU_WALK:
  800.       if (EditingCurve != -1)
  801.     break;
  802.       Walking = !Walking;
  803.       if (Walking) {
  804.         agvSetAllowIdle(0);
  805.     glutIdleFunc(IncrementStep);    
  806.       } else {
  807.         agvSetAllowIdle(1);
  808.       }
  809.       break;
  810.     case CMENU_DONEEDIT:
  811.       glutMouseFunc(CurveHandleButton);
  812.       EditingCurve = -1;
  813.       CurvePickedPoint = -1;
  814.       Walking = WasWalking;
  815.       if (Walking)
  816.     glutIdleFunc(IncrementStep);
  817.       else
  818.         agvSetAllowIdle(1);
  819.       glutPostRedisplay();
  820.       break;
  821.     case CMENU_RESET:
  822.       FlatCSet();
  823.       ComputeCSetAndMakeLists();
  824.       glutPostRedisplay();
  825.       break;
  826.     case CMENU_MIRROR:
  827.       MirrorLegs = !MirrorLegs;
  828.       ComputeCSetAndMakeLists();
  829.       glutPostRedisplay();      
  830.     }
  831. }
  832.  
  833. void CurveMenuInit(void)
  834. {
  835.   int i;
  836.   char label[3];
  837.  
  838.   if (CurveEditMenu != -1) {
  839.     glutDestroyMenu(CurveEditMenu);
  840.     glutDestroyMenu(CurveMenu);
  841.     glutDestroyMenu(StepSizeMenu);
  842.   }
  843.  
  844.   CurveEditMenu = glutCreateMenu(CurveHandleEditMenu);
  845.   for (i = 0; i < NUM_JOINTS; i++) {
  846.     sprintf(label, " %d ", i+1);
  847.     glutAddMenuEntry(label, i);
  848.   }
  849.   StepSizeMenu = glutCreateMenu(CurveHandleSZMenu);
  850.   glutAddMenuEntry("0.25", 25);
  851.   glutAddMenuEntry("0.5",  50);
  852.   glutAddMenuEntry("1.0", 100);
  853.   glutAddMenuEntry("2.0", 200);
  854.   glutAddMenuEntry("3.0", 300);
  855.   glutAddMenuEntry("5.0", 500);
  856.   CurveMenu = glutCreateMenu(CurveHandleMenu);
  857.   glutAddSubMenu("Load Curve Set", LoadMenu);
  858.   glutAddSubMenu("Save As Curve Set", SaveMenu);
  859.   glutAddSubMenu("Edit Curve", CurveEditMenu);
  860.   glutAddMenuEntry("Done Editing", CMENU_DONEEDIT);
  861.   glutAddMenuEntry("Flatten Curve Set", CMENU_RESET);
  862.   glutAddMenuEntry("Toggle mirrored", CMENU_MIRROR);
  863.   glutAddSubMenu("Step size", StepSizeMenu);
  864.   glutAddMenuEntry("Toggle dotted", CMENU_CURVE);
  865.   glutAddMenuEntry("Toggle horizontals", CMENU_HORIZ);
  866.   glutAddMenuEntry("Toggle walking", CMENU_WALK);
  867.   glutAddMenuEntry("Quit", CMENU_QUIT);
  868.   glutAttachMenu(GLUT_RIGHT_BUTTON);
  869. }
  870.  
  871. void CurveVisible(int v)
  872. {
  873.   if (v == GLUT_VISIBLE)
  874.     CurveWindowVisible = 1;
  875.   else 
  876.     CurveWindowVisible = 0;
  877. }
  878.  
  879. /***************************************************************/
  880. /*********************** GUY WINDOW ****************************/
  881. /***************************************************************/
  882.  
  883. void GuyDisplay(void)
  884. {
  885.   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  886.   glFlush();
  887.  
  888.   glLoadIdentity();
  889.  
  890.   agvViewTransform();
  891.  
  892.   if (DrawAxes)
  893.     glCallList(AxesList);
  894.  
  895.   switch(GuyModel) {
  896.     case WIRECUBE:   DrawTheGuy_WC();  break;
  897.     case SOLIDCUBE:  DrawTheGuy_SC();  break;
  898.     case CYLINDER1:  DrawTheGuy_SL();  break;
  899.     case CYLINDER2:  DrawTheGuy_SL2(); break;
  900.   }
  901.  
  902.   glutSwapBuffers();
  903.   glFlush();
  904. }
  905.  
  906. void GuyReshape(int w, int h)
  907. {
  908.   glViewport(0,0,w,h);
  909.   glMatrixMode(GL_PROJECTION);
  910.   glLoadIdentity();
  911.   if (ViewPerspective)
  912.     gluPerspective(60.0, (GLdouble)w/h, 0.01, 100);
  913.   else
  914.     glOrtho(-1.2, 1.2, -1.2, 1.2, 0.1, 100);
  915.   glMatrixMode(GL_MODELVIEW);
  916.   glFlush();
  917. }
  918.  
  919.  
  920. void GuyGLInit(void)
  921. {
  922.   GLfloat mat_ambient[] = { 1.0, 1.0, 1.0, 1.0 };
  923.   GLfloat light_position[] = { 0.3, 0.5, 0.8, 0.0 };
  924.   GLfloat lm_ambient[] = { 0.2, 0.2, 0.2, 1.0 };
  925.   
  926.   glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient);
  927.   glLightfv(GL_LIGHT0, GL_POSITION, light_position);
  928.   glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lm_ambient);
  929.   
  930.   glEnable(GL_LIGHTING);
  931.   glEnable(GL_LIGHT0);
  932.   glDepthFunc(GL_LESS);
  933.   glEnable(GL_DEPTH_TEST);
  934.   glEnable(GL_NORMALIZE);
  935.   glShadeModel(GL_SMOOTH);
  936.   /* Cylinder stuff */
  937.   StoreTheGuy_SL();
  938.   StoreTheGuy_SL2();
  939. }
  940.  
  941. void GuyHandleKeys(unsigned char key, int x, int y)
  942. {
  943.   switch(key) {
  944.     case 'f':
  945.     case ' ': Step++;
  946.               StopWalking(); break;
  947.     case 'F': Step += 5;
  948.               StopWalking(); break;
  949.     case 'b': Step--;
  950.               StopWalking(); break;
  951.     case 'B': Step -= 5; 
  952.               StopWalking(); break;
  953.   }
  954.   Step %= CYCLE_SIZE;
  955.   if (Step < 0)
  956.     Step = CYCLE_SIZE + Step;
  957.   agvHandleKeys(key, x, y);
  958.   RedisplayBoth();
  959. }
  960.  
  961. typedef enum { GMENU_QUIT, GMENU_CURVE, GMENU_HORIZ,
  962.                GMENU_AXES, GMENU_PERSP } GuyMenuChoices;
  963.  
  964.  
  965. void GuyModelHandleMenu(int model)
  966. {
  967.   GuyModel = model;
  968.   if (model == WIRECUBE)
  969.     glDisable(GL_LIGHTING);
  970.   else
  971.     glEnable(GL_LIGHTING);
  972.   glutPostRedisplay();
  973. }
  974.  
  975. void GuyHandleMenu(int value)
  976. {
  977.   switch (value) {
  978.     case GMENU_QUIT:
  979.       exit(0);
  980.       break;
  981.     case GMENU_AXES:
  982.       DrawAxes = !DrawAxes;
  983.       glutPostRedisplay();
  984.       break;
  985.     case GMENU_PERSP:
  986.       ViewPerspective = !ViewPerspective;
  987.       GuyReshape(glutGet(GLUT_WINDOW_WIDTH), glutGet(GLUT_WINDOW_HEIGHT));
  988.       glutPostRedisplay();
  989.       break;
  990.   }
  991. }
  992.  
  993. void GuyMenuInit(void)
  994. {
  995.   int sub2, sub1 = glutCreateMenu(agvSwitchMoveMode);
  996.   glutAddMenuEntry("Flying move",  FLYING);
  997.   glutAddMenuEntry("Polar move",   POLAR);
  998.   sub2 = glutCreateMenu(GuyModelHandleMenu);
  999.   glutAddMenuEntry("Wire cubes",  WIRECUBE);
  1000.   glutAddMenuEntry("Solid cubes", SOLIDCUBE);
  1001.   glutAddMenuEntry("Cylinder 1",  CYLINDER1);
  1002.   glutAddMenuEntry("Cylinder 2",  CYLINDER2);
  1003.   glutCreateMenu(GuyHandleMenu);
  1004.   glutAddSubMenu("Viewing", sub1);
  1005.   glutAddSubMenu("Model", sub2);
  1006.   glutAddMenuEntry("Toggle Axes",    GMENU_AXES);
  1007.   glutAddMenuEntry("Toggle Perspective View", GMENU_PERSP);
  1008.   glutAddMenuEntry("Quit",           GMENU_QUIT);
  1009.   glutAttachMenu(GLUT_RIGHT_BUTTON);
  1010. }
  1011.  
  1012. /***************************************************************/
  1013. /********************* BOTH WINDOWS ****************************/
  1014. /***************************************************************/
  1015.  
  1016. void RedisplayBoth(void)
  1017. {
  1018.   glutSetWindow(GuyWindow);
  1019.   glutPostRedisplay();
  1020.   if (CurveWindowVisible) {
  1021.     glutSetWindow(CurveWindow);
  1022.     glutPostRedisplay();
  1023.   }
  1024. }
  1025.  
  1026. void IncrementStep(void)
  1027. {
  1028.   fStep = fmod(fStep + IncStep, CYCLE_SIZE);
  1029.   Step = (int)fStep;
  1030.   if (agvMoving)
  1031.     agvMove();
  1032.   RedisplayBoth();
  1033. }
  1034.  
  1035. void StopWalking(void)
  1036. {
  1037.   if (Walking) {
  1038.     Walking = 0;
  1039.     agvSetAllowIdle(1);
  1040.   }
  1041. }
  1042.  
  1043. void SetWindowTitles(char *csetname)
  1044. {
  1045.   char windowtitle[MAX_CSETNAMELEN + 20];
  1046.  
  1047.   strcpy(windowtitle, "Rotation Curves: ");
  1048.   strcat(windowtitle, csetname);
  1049.   glutSetWindow(CurveWindow);
  1050.   glutSetWindowTitle(windowtitle);
  1051.  
  1052.   strcpy(windowtitle, "The Guy: ");
  1053.   strcat(windowtitle, csetname);
  1054.   glutSetWindow(GuyWindow);
  1055.   glutSetWindowTitle(windowtitle);
  1056. }
  1057.  
  1058. /***************************************************************/
  1059. /***************************** MAIN ****************************/
  1060. /***************************************************************/
  1061.  
  1062. void main(int argc, char** argv)
  1063. {
  1064.   glutInit(&argc, argv);
  1065.  
  1066.   glutInitWindowSize(512, 512);
  1067.   glutInitWindowPosition(700, 250);
  1068.   glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
  1069.   GuyWindow = glutCreateWindow("The Guy:");
  1070.   agvInit(!Walking);
  1071.   AxesList = glGenLists(1);
  1072.   agvMakeAxesList(AxesList);
  1073.   GuyGLInit();
  1074.   GuyMenuInit();
  1075.   glutDisplayFunc(GuyDisplay);
  1076.   glutReshapeFunc(GuyReshape);
  1077.   glutKeyboardFunc(GuyHandleKeys);
  1078.  
  1079.   glutInitWindowSize(512, 1024);
  1080.   glutInitWindowPosition(100, 0);
  1081.   glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
  1082.   CurveWindow = glutCreateWindow("Rotation Curves:");
  1083.   CurveGLInit();
  1084.   glutDisplayFunc(CurveDisplay);
  1085.   glutReshapeFunc(CurveReshape);
  1086.   glutMouseFunc(CurveHandleButton);
  1087.   glutMotionFunc(CurveHandleMotion);
  1088.   glutKeyboardFunc(CurveHandleKeys);
  1089.   glutVisibilityFunc(CurveVisible);
  1090.  
  1091.   FlatCSet();
  1092.   MakeLists();
  1093.  
  1094.   if (MakeLoadAndSaveMenus() > 0)  /* read first curve if there was one */
  1095.     HandleLoadMenu(0);
  1096.  
  1097.   CurveMenuInit();
  1098.  
  1099.   glutMainLoop();
  1100. }
  1101.  
  1102.  
  1103.  
  1104.  
  1105.